<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>React面试题</title>
    <link rel="stylesheet" href="../1style/index.css"/>
    <script src="../1style/jquery.js"></script>
</head>
<body>
<h1>React面试题</h1>
https://blog.csdn.net/Zervih/article/details/114239783

<h3>聊聊React,能干什么[开放题]</h3>
<div>
    <pre>
      用于构建UI的js库,采用MVC架构
      setState设置数据发生变化,就render驱动视图发生变化
      和vue已基本一样,需要借助UI框架库,router,store构建完整的项目
    </pre>
</div>

<h3>React16/17/18版本的区别</h3>
<div>
    <pre>
        1.生命周期的改变 2.组件创建方式改变
        3.15是全量渲染方式改变(会卡顿) 16采用了新的核心架构React Fiber
        16.3废弃了componentWillMount、componentWillReceiveProps、componentWillUpdate生命周期。
            新增 static getDerivedStateFromProps、getSnapshotBeforeUpdate.
        handleChange(e)=> { // v16中,在异步方法中是拿不到e的，需要事先执行e.persist()
            e.persist();setTimeout(() => console.log(e), 1000);
        }
        useEffect(() => () => {//浏览器渲染完毕后执行})//副作用清理函数(如果存在)改为异步执行，即在浏览器渲染完毕后执行。
        // forwardRef 和 memo组件的行为会与常规函数组件和class组件保持一致。它们在返回undefined时会报错。
        const Button = forwardRef(() => {
        <!--<button/>;--> // 这里忘记写return，所以返回了undefined // React17不会忽略检测它，会返回err
        });
        const Button = memo(() => {
        <!--<button/>; -->// 这里忘记写return，所以返回了undefined  // React17不会忽略检测它，会返回err
        });

你需要调用 e.persist()，它会将当前的合成事件从事件池中删除，并允许保留对事件的引用。

事件池：合成事件对象会被放入池中统一管理。这意味着合成事件对象可以被复用，当所有事件处理函数被调用之后，其所有属性都会被回收释放置空

React16会用babel-loader编译JSX模版为React.createElement()
import React from "react";
在v16中，我们写一个React组件，总要引入import React from 'react' // 同时需要babel-loader支持
在v17中, 就不需要了 https://segmentfault.com/a/1190000042680491

17改进：
1.不在document对象上绑定事件,绑定在rootNode节点(事件代理更改)
// e.stopPropagation() // v16无效
// e.nativeEvent.stopImmediatePropagation() // 阻止监听同一事件的其他事件监听器被调用

副作用清理函数(如果存在)改为异步执行，即在浏览器渲染完毕后执行useEffect
React18放弃了对ie11的支持，如需兼容，需要回退到 React17版本
退出批量更新，你可以使用 flushSync

    </pre>
</div>

<h3>jsx的理解</h3>
<div>
    <pre>
        jsx就是React.createElement的语法糖,jsx就更好看,直观,最终通过babel转换为React.createElement
        jsx工作原理 就是 抽象语法树, 返回的 是一个虚拟Dom
        1.jsx必须要有根节点 2.正常的普通HTML元素要小写，如果是大写，默认认为是组件
        虚拟Dom 处理了 浏览器的差异  可以实现 差异化更新
    </pre>
</div>

<h3>虚拟DOM的理解</h3>
<div>
    <pre>
        https://www.bilibili.com/video/BV1bK4y1a7f2
        描述真实DOM的的一个对象,跨端的,也解决了兼容性问题
        1.初次渲染的时候不一定快,更新的时候快,精准的定点更新
    </pre>
</div>

<h3>refs的理解</h3>
<div>
    <pre>
        字符串this.refs.
        refElement = React.createRef(); 对象中存在 current // <!--<input ref={this.refElement}></input>-->
        回调Refs 传入函数，该函数会在 DOM 被挂载时进行回调，这个函数会传入一个 <!--<input ref={ ref => this.refElement = ref }></input>-->
        传入hook，hook是通过 useRef() 方式创建 <!--const element = useRef(null);-->

ref可以挂载到html元素上，挂载在React组件上,可以获取DOM和组件
import { findDOMNode } from 'react-dom'; //findDOMNode可以获取真实的DOM
console.log(findDOMNode(this.refs.child));

拿不到子组件的实例，还需要使用forwaRef
const Child: React.FC = forwardRef((props,ref) => {
// 暴露组件内 属性方法
 useImperativeHandle(ref, () => ({
    value: inputRef.current.value
  }));
  return <!--<input type="text" ref={ref}/>-->
})

    </pre>
</div>

<h3>Hooks 使用规则</h3>
<div>
    <pre>
        只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
        只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。
        ）还有一个地方可以调用 Hook —— 就是自定义的 Hook 中

        hook解决的问题
        在组件间复用状态逻辑很难
        复杂组件变得难以理解，高阶组件和函数组件的嵌套过深。
        class组件的this指向问题
        难以记忆的生命周期
    </pre>
</div>

<h3>自定义Hooks</h3>
<div>
    <pre>
        https://www.bilibili.com/video/BV1nM411b7tq
        可重用性:自定义Hooks可以在多个组件中重用
        可维护性:将状态和副作用逻辑提取到单独的Hooks中
        更好的组件分离: Hooks提供了一种统一的方式来管理状态和逻辑
        自动以Hook就是抽离组件中的通用函数部分,不抽离ui视图html
        自定义hook以use开头,函数内部使用官方hook改变视图
    </pre>
</div>

<h3>react渲染流程</h3>
<div>
    <pre>
        https://xiaochen1024.com/series/60b1b600712e370039088e24
        https://www.jianshu.com/p/1692fdc38ca1
        https://zhuanlan.zhihu.com/p/370183031
        异步可中断
        增量更新
        如果是动画用requestAnimation最高效的
    </pre>
</div>

<h3>介绍下React的Fiber架构</h3>
<div>
    <pre>
        Fiber是一套架构,用于解决15版本递归循环diff,前端渲染容易出现卡顿白屏的
        Fiber在Virtual DOM 上重建了树和节点结构，叫做 fiber 树和 fiber 节点。
        children树和链表树,Fiber树是深度优先遍历
            Scheduler（调度器）—— 调度任务的优先级，高优任务优先进入Reconciler
            Reconciler（协调器）—— 负责找出变化的组件
            Renderer（渲染器）—— 负责将变化的组件渲染到页面上
    </pre>
</div>

<h3>React异步渲染的概念，介绍TimeSlicing和Suspense</h3>
<div>
    <pre>
        https://juejin.cn/post/6995744573989322789
    </pre>
</div>

<h3>重新渲染Render会做些什么</h3>
<div>
    <pre>
      render是'react-dom'解构来的
      把JXS变成React.createElement(HTML标签,[props],[...children])
      componentWillReceiveProps(){} // 更①
      shouldComponentUpdate(){} // 更②
      componentWllUpdate(){}		//更③
      render() //④必须有这个
      componentDidMount(){}   //⑤ http请求放在这个生命周期里
      componentDidUpdate(){}  //⑥
      componentWllUnmount(){} //⑦
    </pre>
</div>

<h3>React的上下文?解决了什么问题</h3>
<div>
    <pre>
        https://www.bilibili.com/video/BV19v411z7mC/
        核心概念：Context(执行上下文)、Provider(发布者)、Consumer(订阅者)
        const {Provider, Consumer} = React.createContext(defaultValue);
        为跨层级的组件传值。
    </pre>
</div>

<h3>介绍下Redux整个流程原理,Redux的过程,接入流程,工作流程,数据流的流程</h3>
<div>
    <pre>
        https://www.bilibili.com/video/BV1At41137DG?p=23
    </pre>
</div>

<h3>介绍Redux，主要解决什么问题</h3>
<div>
    <pre>
        Redux可预测化的状态管理,就是一个数据仓库,全局状态管理
        主要解决:单向数据流,组件之间的数据通信
    </pre>
</div>

<h3>介绍下React组件</h3>
<div>
    <pre>
        函数组件 无状态组件 木偶组件 Ui组件
        类组件   有状态组件 智能组件 功能组件
        受控组件 非受控组件 高阶组件
    </pre>
</div>

<h3>介绍下React高阶组件，普通组件有什么区别</h3>
<div>
    <pre>
      高阶组件(HOC) 就是一个函数，且该函数接受一个组件作为参数，并返回一个新的组件
      1.代码复用2.渲染劫持3.抽象化和操作状态（state）4.操作属性（props）
      有点像vue的mixin
    </pre>
</div>

<h3>介绍React-redux常用的中间件</h3>
<div>
    <pre>
        redux-thunk redux-saga
    </pre>
</div>

<h3>React组件之间如何传值</h3>
<div>
    <pre>
        父=>子 传值 子接收:this.props.name
        子=>父 传值 回调传参
        Context组件
        7.全局变量 以用 window.x
    </pre>
</div>

<h3>哪些方法会触发React重新渲染</h3>
<div>
    <pre>
        // https://blog.csdn.net/qq_32198115/article/details/127961113
        1、setState() // this.setState({}); 页面会渲染
        2、props发生变化
        3、forceUpdate()
    </pre>
</div>

<h3>React性能优化方案</h3>
<div>
    <pre>
        props/state/center 发送改变的时候 组件就会更新
        合理分割组件就能带来性能上的优化,把变化的ui视图封装成一个组件
        https://www.bilibili.com/video/BV1Yr4y1J7oc/
        1.开发阶段的优化 2.打包的优化 3.上线的优化
        1.减少不必要的组件更新
        利用缓存可以考虑使用PureComponent、React.memo、hook函数useCallback、useMemo等方法
        组件懒加载
        不要使用内联函数定义
        组件卸载-清除定时器
        https://blog.csdn.net/weixin_43484007/article/details/124366452
        bilibili.com/video/BV1s3411L7Cm
    </pre>
</div>

<h3>props和state的区别,触发更新的生命周期分别有什么区别</h3>
<div>
    <pre>
        props 是组件的只读属性,用函数回调进行赋值
        props 中的参数设置一个 defaultProps
        this.setState进行赋值
    </pre>
</div>

<h3><span>命中</span>React/Vue中的key的作用,写key和不写key执行的区别</h3>
<div>
    <pre>
      \vue\src\core\vdom\patch.js updateChildren
      key的作用就是更新组件时判断两个节点是否相同。相同就复用，不相同就删除旧的创建新的。
      推荐使用key,不使用key数据发生变化会删除对应dom上事件
      https://www.bilibili.com/video/BV127411P7zi
    </pre>
</div>

<h3>render函数中return如果没有使用()会有什么问题？</h3>
<div>
    <pre>
    没有问题
    但是如果你return，后面再换行就有问题了， 所以一般用小括号包住
    </pre>
</div>


<h3>React中setState的原理</h3>
<div>
    <pre>
        https://www.bilibili.com/video/BV1n24y1y7iZ
    </pre>
</div>

<h3>React中setState后发生了什么?</h3>
<div>
    <pre>
        shouldComponentUpdate
        componentWillUpdate
        render
        componentDidUpdate
    </pre>
</div>
<h3>setState是同步还是异步</h3>
<div>
    <pre>
        1.在react能控制的是异步
        2.setTimeOut/原生事件中
        3.react18全是异步
        setState进行多次执行，在react执行合并多次为一次情况下，相当于后面覆盖前面，相当于加一次。
    </pre>
</div>

<h3>React-Router怎么实现路由切换</h3>
<div>
    <pre>
        hashRouter路游
        原生js实现hashRouter主要是监听它的hashchange事件的变化，然后拿到对应的location.hash更新对应的视图
        能够实现history路由跳转不刷新页面得益与H5提供的pushState(),replaceState()等方法，
        这些方法都是也可以改变路由状态（路径），但不作页面跳转，我们可以通过location.pathname来显示对应的视图
        BrowserRouter路游
        并监听popstate事件,所以我们要用Consumer, Provider跨组件通信
        Link组件主要做的是，拿到prop,传进来的to,通过PushState()改变路由状态，
        然后拿到BrowserRouter传过来的onChangeView手动刷新视图
    </pre>
</div>

<h3>React路由懒加载-组件懒加载</h3>
<div>
    <pre>
        https://www.bilibili.com/video/BV1Kq4y1F7vY
        最流行的库 react-loadable
        const OtherComponent = React.lazy(() => import('./OtherComponent'));
        <!--<Suspense fallback={'Loading'}>
            <OtherComponent></OtherComponent>
        </Suspense>-->
    </pre>
</div>

<h3>React-Router里的＜Link＞标签和＜a＞标签有什么区别</h3>
<div>
    <pre>
    <!--
    <Link>标签是react-router-dom下的元素，一般配合 <Route> 使用
    <a>是html原生标签
    两者都实现页面跳转，<Link>无刷新，<a>进行刷新
    出现上面现象的原因<a>标签在涉及到path变化后浏览器的原生反应就是会刷新页面
    <Link>渲染后默认也是a标签,在<Link>内部的实现原理是通过history进行了跳转，并且event.preventDefault()阻止了a标签的默认事件
    禁掉 a 标签的默认事件，可以在点击事件中执行 event.preventDefault();
    禁掉默认事件的 a 标签 可以使用 history.pushState() 来改变页面 url，这个方法还会触发页面的 hashchange 事件，Router 内部通过捕获监听这个事件来处理对应的跳转逻辑。
    -->
    </pre>
</div>

<h3>React组件中事件代理的原理,怎么做事件代理</h3>
<div>
    <pre>
React 并不会把所有的处理函数直接绑定在真实的节点上。而是把所有的事件绑定到结构的最外层，使用一个统一的事件监听器，这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。
当组件挂载或卸载时，只是在这个统一的事件监听器上插入或删除一些对象。
当事件发生时，首先被这个统一的事件监听器处理，然后在映射里找到真正的事件处理函数并调用。
这样做的优点是解决了兼容性问题，并且简化了事件处理和回收机制（不需要手动的解绑事件，React 已经在内部处理了）。但是有些事件 React 并没有实现，比如 window 的 resize 事件。
在React@17.0.3版本中：

所有事件都是委托在id = root的DOM元素中（网上很多说是在document中，17版本不是了）；
在应用中所有节点的事件监听其实都是在id = root的DOM元素中触发；
React自身实现了一套事件冒泡捕获机制；
React实现了合成事件SyntheticEvent；
React在17版本不再使用事件池了（网上很多说使用了对象池来管理合成事件对象的创建销毁，那是16版本及之前）；
事件一旦在id = root的DOM元素中委托，其实是一直在触发的，只是没有绑定对应的回调函数；

    </pre>
</div>

<h3>React中Dom结构发生变化后内部经历了哪些变化</h3>
<div>
    <pre>
    React重新构建vnode树
    和旧vnode树对比，得出变化部分Patches(diff算法)
    将Patches更新到真实dom上
    </pre>
</div>

<h3>React的事件机制（绑定一个事件到一个组件上）合成事件</h3>
<div>
    <pre>
    （1）对原生事件的封装
    （2）不同浏览器事件兼容的处理
    （3）绑定到顶层document
    经过遍历把事件处理函数存储到 listenerBank(一个对象)中，缓存起来，dispatchEvent方法统一进行派发的
    浏览器事件的执行需要经过三个阶段，捕获阶段-目标元素阶段-冒泡阶段。
    </pre>
</div>

<h3>React.PureComponet</h3>
<div>
    <pre>
        PureComponet内部自动实现了shouldComponentUpdate 钩子 不需要手动比较
        纯组件内部分别对比前后俩次props和state的值，来决定是否重新渲染组件
        如果没有数据的变化，则不会重新渲染组件
        数据值 浅层对比 所以对象有坑
    </pre>
</div>


</body>
</html>

<script>
    $(function () {
        $("h3").click(function () {
            $(this).next().toggle();
        });
    })
</script>

